﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Reflection;

namespace Seven.Tools.Extension
{
    /// <summary>
    /// 提供一组对 公开枚举数类型 <see cref="System.Collections.IEnumerable"/> 操作方法的扩展。
    /// </summary>
    public static class EnumerableExtensions
    {
        /// <summary>
        /// 判断指定的序列对象 <paramref name="_this"/> 是否为 Null 或不包含任何元素。
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="_this">被判断的序列 <see cref="IEnumerable"/> 对象。</param>
        /// <returns>如果序列对象 <paramref name="_this"/> 为 Null 或者不包含任何元素，则返回 true；否则返回 false。</returns>
        public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> _this)
        {
            return _this == null || _this.Count() == 0;
        }

        /// <summary>
        /// 将一个 普通枚举序列 <see cref="System.Collections.IEnumerable"/> 转换成一个泛型枚举序列 <see cref="System.Collections.Generic.IEnumerable&lt;Object&gt;"/>。
        /// </summary>
        /// <param name="_this">被转换的普通枚举序列 <see cref="System.Collections.IEnumerable"/> 对象。</param>
        /// <returns>一个 <see cref="System.Collections.Generic.IEnumerable&lt;Object&gt;"/>，包含输入序列中所有的元素。</returns>
        public static IEnumerable<object> ToGeneric(this IEnumerable _this)
        {
            if (_this == null)
            { return System.Linq.Enumerable.Empty<object>(); }

            return _this.OfType<object>();
        }

        /// <summary>
        /// 返回源序列 <paramref name="_this"/> 中的一个子集。
        /// </summary>
        /// <typeparam name="TSource"><paramref name="_this"/> 中的元素的类型。</typeparam>
        /// <param name="_this">一个 <see cref="System.Collections.Generic.IEnumerable&lt;TSource&gt;"/>，用于从中返回元素。</param>
        /// <param name="startIndex">返回剩余元素前要跳过的元素数量，也可理解为范围开始处的从零开始的 <see cref="System.Collections.Generic.IEnumerable&lt;TSource&gt;"/> 索引。</param>
        /// <param name="count">范围中的元素数，同时也表示要返回的元素数量。</param>
        /// <returns>一个 <see cref="System.Collections.Generic.IEnumerable&lt;TSource&gt;"/>，它表示源序列 <paramref name="_this"/> 中的一个子集。</returns>
        public static IEnumerable<TSource> GetRange<TSource>(this IEnumerable<TSource> _this, int startIndex, int count)
        {
            return _this.Skip(startIndex).Take(count);
        }

        /// <summary>
        /// 将一个泛型序列转换成一个 <see cref="DataTable"/>，表格中的每个 DataRow 表示泛型序列中的一个元素。
        /// </summary>
        /// <typeparam name="TSource">泛型序列中元素的类型。</typeparam>
        /// <param name="_this">一个要进行转换操作的泛型序列。</param>
        /// <returns>返回一个 <see cref="DataTable"/>，表格中的每个 DataRow 表示泛型序列中的一个元素</returns>
        public static DataTable ToDataTable<TSource>(this IEnumerable<TSource> _this)
        {
            Type type = typeof(TSource);
            DataTable table = new DataTable(type.Name);

            IEnumerable<PropertyInfo> properties = type.GetProperties().Where(p => p.GetMethod != null);

            foreach (var p in properties)
            {
                DataColumn column = new DataColumn(p.Name);
                column.DataType = p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)
                    ? Nullable.GetUnderlyingType(p.PropertyType)
                    : p.PropertyType;
                table.Columns.Add(column);
            }

            foreach (TSource item in _this)
            {
                DataRow row = table.NewRow();
                foreach (PropertyInfo p in properties)
                {
                    object value = p.GetValue(item);
                    row[p.Name] = value == null ? DBNull.Value : value;
                }
                table.Rows.Add(row);
            }
            return table;
        }

        /// <summary>
        /// 将源序列按指定字段升序排序后返回。若源序列为空集，则返回源序列。
        /// </summary>
        /// <typeparam name="TSource">泛型序列中元素的类型。</typeparam>
        /// <typeparam name="TKey">排序字段的类型。</typeparam>
        /// <param name="_this">一个要进行转换操作的泛型序列。</param>
        /// <param name="keySelector">用于从元素中提取键的函数。</param>
        /// <returns></returns>
        public static IEnumerable<TSource> TryOrderBy<TSource, TKey>(this IEnumerable<TSource> _this, Func<TSource, TKey> keySelector)
        {
            if (_this.Count() == 0) { return _this; }
            return _this.OrderBy(keySelector);
        }

        /// <summary>
        /// 将源序列按指定字段降序排序后返回。若源序列为空集，则返回源序列。
        /// </summary>
        /// <typeparam name="TSource">泛型序列中元素的类型。</typeparam>
        /// <typeparam name="TKey">排序字段的类型。</typeparam>
        /// <param name="_this">一个要进行转换操作的泛型序列。</param>
        /// <param name="keySelector">用于从元素中提取键的函数。</param>
        /// <returns></returns>
        public static IEnumerable<TSource> TryOrderByDescending<TSource, TKey>(this IEnumerable<TSource> _this, Func<TSource, TKey> keySelector)
        {
            if (_this.Count() == 0) { return _this; }
            return _this.OrderByDescending(keySelector);
        }
    }
}
